package cc.shacocloud.mirage.kotlin.restful

import cc.shacocloud.mirage.restful.bind.annotation.GetMapping
import cc.shacocloud.mirage.restful.bind.annotation.RequestMapping
import cc.shacocloud.mirage.restful.bind.annotation.RestController
import cc.shacocloud.mirage.restful.example.ExampleServer
import cc.shacocloud.mirage.utils.reflection.DefaultParameterNameDiscoverer
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.LoggerContext
import io.vertx.core.AsyncResult
import io.vertx.core.Vertx
import io.vertx.core.buffer.Buffer
import io.vertx.ext.web.client.HttpResponse
import io.vertx.ext.web.client.WebClient
import io.vertx.junit5.VertxExtension
import io.vertx.junit5.VertxTestContext
import kotlinx.coroutines.delay
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.slf4j.LoggerFactory
import java.util.function.Function

/**
 * @author 思追(shaco)
 *
 */
@ExtendWith(VertxExtension::class)
internal class KotlinRequestMappingHandlerTest {

    @BeforeEach
    fun initServer() {
        val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext
        loggerContext.getLogger("root").level = Level.INFO
        loggerContext.getLogger("cc.shacocloud.mirage").level = Level.DEBUG

        val vertx = Vertx.vertx()

        ExampleServer.startServer(
            vertx,
            9090,
            { v -> KotlinRequestMappingHandler(v, DefaultParameterNameDiscoverer()) },
            ExampleController()
        )
    }

    @RestController
    @RequestMapping("/api/example")
    open class ExampleController {

        @GetMapping("/test-coroutines")
        suspend fun testCoroutines(): Any {
            delay(1000)
            return mapOf("message" to "协程方法调用成功！")
        }

        @GetMapping("/test")
        suspend fun test(): Any {
            return mapOf("message" to "普通方法调用成功！")
        }

    }

    private fun exec(
        vertx: Vertx,
        testContext: VertxTestContext,
        requestFun: Function<WebClient, io.vertx.ext.web.client.HttpRequest<Buffer>>
    ) {
        val client: WebClient = WebClient.create(vertx)
        requestFun.apply(client).send { ar: AsyncResult<HttpResponse<Buffer>> ->
            if (ar.failed()) {
                testContext.failNow(ar.cause())
            } else {
                val response = ar.result()
                println()
                println("响应状态码：" + response.statusCode())
                println("响应状态消息：" + response.statusMessage())
                println("响应结果体：" + response.body())
                testContext.completeNow()
            }
        }
    }

    /**
     * 测试协程内部不阻塞方法
     */
    @Test
    fun test(vertx: Vertx, testContext: VertxTestContext) {
        exec(vertx, testContext) { client ->
            client.get(9090, "127.0.0.1", "/api/example/test")
        }
    }

    /**
     * 测试协程内部阻塞方法
     */
    @Test
    fun testCoroutines(vertx: Vertx, testContext: VertxTestContext) {
        exec(vertx, testContext) { client ->
            client.get(9090, "127.0.0.1", "/api/example/test-coroutines")
        }
    }
}
